#!/bin/python


import requests
import hjson
from PIL import Image

import os
import logging
from urllib import urlencode
import json
import time
from StringIO import StringIO



#login_url = "https://account.xiaomi.com/pass/serviceLogin"
#auth_url = "https://account.xiaomi.com/pass/serviceLoginAuth2"

def pick_str(target, start, end):
	idx_s = target.find(start)
	#print idx_s
	if idx_s == -1:
		return None
	idx_s += len(start)
	idx_e = target.find(end, idx_s)
	#print idx_e
	if idx_e == -1:
		return None
	return (idx_s, idx_e)


DEFAULT_SERVICE_ID = "mi_eshopm"
DEFAULT_USER_AGENT = "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19"

class MiShop():

	def __init__(self):
		pass

	def getAuthorizeSSO(self):
		url='http://m.mi.com/mshopapi/index.php/v1/authorize/sso?client_id=180100031013&sns=qq&callback=http%3A%2F%2Fm.mi.com%2Findex.html%23ac%3Daccount%26op%3Dindex'

		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'no-cache',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
			#'Referer': 'http://m.mi.com/index.html',
		}

		r = requests.get(url, headers=headers, allow_redirects=False)
		tag = "getAuthorizeSSO"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))

		return r.headers['location']


	def getServiceLogin(self, session, url):
		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'no-cache',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19',
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
			#'Referer': 'http://m.mi.com/index.html',
		}

		r = session.get(url, headers=headers)
		
		tag = "getServiceLogin"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))

		meta = {}

		text = r.text
		pos = pick_str(text, 'callback:"', '",')
		meta['callback'] = text[ pos[0] : pos[1]]
		#print meta

		text = text[pos[1]:]
		pos = pick_str(text, 'qs:"', '",')
		meta['qs']  = text[ pos[0] : pos[1]]
		#print meta

		text = text[pos[1]:]
		pos = pick_str(text, '"_sign":"', '",')
		meta['_sign']  = text[ pos[0] : pos[1]]
		logging.info("[%s] meta: %s" % (tag, meta))

		return meta


	def loginByPassword(self, session, user, passwd, referer, meta):
		auth_url = "https://account.xiaomi.com/pass/serviceLoginAuth2"
		payload = {'user': user,
			   'pwd': passwd,
			   #'_sign' : ,
			   #'qs': ,
			   #'callback': ,
			   'sid': DEFAULT_SERVICE_ID,
			   'captCode':'',
			   'hidden': '',
			   'serviceParam':'{"checkSafePhone":false}',
			   '_json': 'true'}
		payload.update(meta)

		#payload='user=weidehao%40163.com&_json=true&pwd=xiaomi.com&' + urlencode({'callback': meta['callback']})
		#payload+='&sid=mi_eshopm&' + urlencode({'qs': meta['qs']})
		#payload+='&hidden=&' + urlencode({'_sign': meta['_sign']})
		#payload+='&serviceParam=%7B%22checkSafePhone%22%3Afalse%7D&captCode='

		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'no-cache',
			'Origin': 'https://account.xiaomi.com',
			'User-Agent': DEFAULT_USER_AGENT,
			'Content-Type': 'application/x-www-form-urlencoded',
			'Accept': '*/*',
			'Accept-Encoding': 'gzip,deflate',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
			'Referer': referer
		}

		r = session.post(auth_url, headers=headers, data=payload)

		tag = "loginByPassword"
		logging.debug("[%s] url: %s" % (tag, auth_url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))
		#logging.debug("[%s] %s" % (tag, r.json()))

		data = r.text.replace("&&&START&&&", '')
		auth_meta = json.JSONDecoder().decode(data)
		logging.info("[%s] auth: %s" % (tag, auth_meta))

		return auth_meta


	def getAuthService(self, session, auth_meta):
		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'no-cache',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
			#'Referer': 'http://m.mi.com/index.html',
		}

		url = "https://account.xiaomi.com" + auth_meta['location']

		r = session.get(url, headers=headers, allow_redirects=False)
		
		tag = "getAuthService"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))

		location = r.headers['location']
		logging.debug("[%s] location: %s" % (tag, location))
		return location


	def getSSOCallback(self, session, url):
		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'no-cache',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
		}

		r = session.get(url, headers=headers, allow_redirects=False)
		
		tag = "getSSOCallback"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))


	def getOpenBuy(self, session):
		url = 'http://s1.mi.com/m/stopen/buy/index/m/v3/index.html'
		
		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'max-age=0',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
			'Referer': 'http://m.mi.com/v2.html',
		}

		r = session.get(url, headers=headers)
		
		tag = "getOpenBuy"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))

		# parse product info
		pos = pick_str(r.text, '_DATA=', '}(this)')
		goods_data = text[ pos[0] : pos[1]]
		logging.debug("[%s] goods data: %s" % (tag, goods_data))

		goods_data = hjson.loads(goods_data)
		logging.info("[%s] goods data: %s" % (tag, goods_data))

		for one in goods_data["goods"]:
			print one["name"]
			for item in one["item"]:
				print "\t%d: %s" % (item, goods_data["success"][str(item)]["name"])


	def getPath(self, session):
		msecs = int(time.time() * 1000)
		url = 'http://tp.hd.mi.com/getpath/cn?m=3&_=%d&jsonpcallback=getpath' % (msecs)
		
		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'max-age=0',
			'Accept': '*/*',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate',
			'Accept-Language': 'zh-CN, en-US',
			'Referer': 'http://s1.mi.com/m/stopen/buy/index/m/v4/index.html',
			'X-Requested-With': 'com.xiaomi.shop',
			'Accept-Charset': 'utf-8, iso-8859-1, utf-16, *;q=0.7',
			'x-GETzip': 'supported',
		}

		r = session.get(url, headers=headers)
		
		tag = "getPath"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))

		pos = pick_str(r.text, '"path":"', '"}')
		path = r.text[ pos[0] : pos[1]]

		logging.info("[%s] path: %s" % (tag, path))
		return path


	def getSTOpen(self, session, buy_url):
		msecs = int(time.time() * 1000)
		
		headers = {
			'Connection': 'keep-alive',
			'Pragma': 'no-cache',
			'Cache-Control': 'max-age=0',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate',
			'Accept-Language': 'zh-CN, en-US',
			'Referer': 'http://s1.mi.com/m/stopen/buy/index/m/v4/index.html',
			'X-Requested-With': 'com.xiaomi.shop',
			'Accept-Charset': 'utf-8, iso-8859-1, utf-16, *;q=0.7',
			'x-GETzip': 'supported',
		}

		r = session.get(buy_url, headers=headers)
		
		tag = "getSTOpen"
		logging.debug("[%s] url: %s" % (tag, buy_url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))


		try:
			text = r.text
			pos = pick_str(text, 'queue:function', '};')
			queue_func = text[ pos[0] : pos[1] ]
			print queue_func
			logging.debug("[%s] queue:function %s" % (tag, queue_func))

			text = queue_func
			pos = pick_str(text, "={", ":function")
			key = text[ pos[0] : pos[1] ]
			logging.debug("[%s] key: %s" % (tag, key))

			text = text[ pos[1] : ]
			pos = pick_str(text, '.cookie("', '")')
			name = text[ pos[0] : pos[1] ]
			logging.debug("[%s] name: %s" % (tag, name))
			dat = session.cookies.get(name)
			logging.debug("[%s] dat: %s" % (tag, dat))

			text = text[ pos[1] + 2 : ] # 2 len('")')
			pos = pick_str(text, ')', ':')
			expr = text[ pos[0] : pos[1] ]
			logging.debug("[%s] expr: %s" % (tag, expr))
			expr = "dat" + expr
			val = eval(expr)
			logging.debug("[%s] val: %s" % (tag, val))

			args = "%s=%s" % (key, val)

			logging.info("[%s] args: %s" % (tag, args))

			return args
		except Exception, msg:
			logging.exception(msg)
			return None


	def getCaptcha(self, session, product):
		msecs = int(time.time() * 1000)
		url = 'http://tp.hd.mi.com/getmode/cn?m=2&product=%s&_r=%d' % (product, msecs)
		
		headers = {
			'Connection': 'keep-alive',
			'Cache-Control': 'max-age=0',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate,sdch',
			'Accept-Language': 'zh-CN, en-US',
			'Referer': 'http://s1.mi.com/m/stopen/buy/index/m/v4/index.html',
			'X-Requested-With': 'com.xiaomi.shop',
			'Accept-Charset': 'utf-8, iso-8859-1, utf-16, *;q=0.7',
			'x-GETzip': 'supported',
		}

		r = session.get(url, headers=headers)
		
		tag = "getCaptcha"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))


 		img = Image.open(StringIO(r.content))

		return img


	def recCaptcha(self, img):
		return None


	def verifyCaptcha(self, session, product, captcha):
		msecs = int(time.time() * 1000)
		url = 'http://tp.hd.mi.com/getmode/cn?vecode=%s&m=2&product=%s&_=%d&callback=getmode' % (captcha, product, msecs)
		
		headers = {
			'Connection': 'keep-alive',
			'Cache-Control': 'max-age=0',
			'Accept': '*/*',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate',
			'Accept-Language': 'zh-CN, en-US',
			'Referer': 'http://s1.mi.com/m/stopen/buy/index/m/v4/index.html',
			'X-Requested-With': 'com.xiaomi.shop',
			'Accept-Charset': 'utf-8, iso-8859-1, utf-16, *;q=0.7',
			'x-GETzip': 'supported',
		}

		r = session.get(url, headers=headers)
		
		tag = "checkCaptcha"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))


		if (r.text == 'getmode({"code":1})'):
			logging.info("[%s] ok" % (tag))


	def hdget(self, session, args, product, captcha, referer):
		msecs = int(time.time() * 1000)
		url = 'http://tp.hd.mi.com/hdget/cn?%s&product=%s&fk=%s&addcart=1&m=2&_=%d&jsonpcallback=hdcontrol' % (args, product, captcha, msecs)
		
		headers = {
			'Connection': 'keep-alive',
			'Cache-Control': 'max-age=0',
			'Accept': '*/*',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate',
			'Accept-Language': 'zh-CN, en-US',
			'Referer': referer,
			'X-Requested-With': 'com.xiaomi.shop',
			'Accept-Charset': 'utf-8, iso-8859-1, utf-16, *;q=0.7',
			'x-GETzip': 'supported',
		}

		r = session.get(url, headers=headers)
		
		tag = "hdget"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))

		pos = pick_str(r.text, '"hdurl":"', '"}')
		token = text[ pos[0] : pos[1]]

		logging.info("[%s] token: %s" % (tag, token))

		return token


	def addCart(self, session, product, token, referer):
		msecs = int(time.time() * 1000)
		url = 'http://m.mi.com/mshopapi/v1/shopping/addcart?product_id=%s&consumption=1&client_id=180100031013&%s&source=bigtap&_=%d&callback=jsonp1' % (product, urlencode({'token': token}), msecs)
		
		headers = {
			'Connection': 'keep-alive',
			'Cache-Control': 'max-age=0',
			'Accept': '*/*',
			'User-Agent': DEFAULT_USER_AGENT,
			'Accept-Encoding': 'gzip,deflate',
			'Accept-Language': 'zh-CN, en-US',
			'Referer': referer,
			'X-Requested-With': 'com.xiaomi.shop',
			'Accept-Charset': 'utf-8, iso-8859-1, utf-16, *;q=0.7',
			'x-GETzip': 'supported',
		}

		r = session.get(url, headers=headers)
		
		tag = "addCart"
		logging.debug("[%s] url: %s" % (tag, url))
		logging.debug("[%s] header: %s" % (tag, r.request.headers))
		#logging.debug("[%s] body: %s" % (tag, r.request.body))
		logging.debug("[%s] cookies: %s" % (tag, requests.utils.dict_from_cookiejar(r.cookies)))
		logging.debug("[%s] text: %s" % (tag, r.text.encode('utf8')))
		
		pos = pick_str(r.text, 'jsonp1({"result":"', '",')
		result = text[ pos[0] : pos[1]]

		if result == "ok":
			logging.info("[%s] success" % (tag))
			return True

		return False

	
	def login(self, usr, pwd):
		auth_sess = requests.Session()
		auth_location = self.getAuthorizeSSO()
		meta = self.getServiceLogin(auth_sess, auth_location)
		auth_meta = self.loginByPassword(auth_sess, usr, pwd, auth_location, meta)
		sso_location = self.getAuthService(auth_sess, auth_meta)
		return sso_location
		

	def open(self, sso_location):
		mi_sess = requests.Session()
		self.getSSOCallback(mi_sess, sso_location)
		self.getOpenBuy(mi_sess)

		# test get captcha ahead 
		#img = self.getCaptcha(mi_sess, product)

		return mi_sess


	def buy(self, mi_sess, product):

		while True:
			try:
				path = self.getPath(mi_sess)
				break
			except Exception, msg:
				logging.exception(msg)
				time.sleep(0.5)

		buy_url = 'http://s1.mi.com/m/stopen/%s/index.html' % (path)

		args = self.getSTOpen(mi_sess, buy_url)
		if  not args:
			args = raw_input("args: ")

		img = self.getCaptcha(mi_sess, product)
		captcha = self.recCaptcha(img)
		if not captcha:
			img.show()
			captcha = raw_input("captcha: ")
		self.verifyCaptcha(mi_sess, product, captcha)

		token = self.hdget(mi_sess, args, product, captcha, buy_url)
		while not self.addCart(mi_sess, product, token, buy_url):
			time.sleep(0.5)


	
usr=''
pwd=''
product=''

if __name__ == "__main__":
	logging.basicConfig(level=logging.DEBUG, format="%(message)s")
	shop = MiShop()
	sso_location = shop.login(usr, pwd)

	sess = shop.open(sso_location)
	if not product:
		product = raw_input("product: ")
	# wait to start
	#time.sleep(1)
	while True:
		try:
			shop.buy(sess, product)
		except Exception, msg:
			logging.exception(msg)
			time.sleep(0.5)
			pass
	
	


